package linux.crontab;

final class CronMgr implements Runnable {
	static void startService() {
		new Thread(_this, "cron").start();
	}

	static void notifyCronQueue() {
		synchronized (_lock) {
			_lock.notifyAll();
		}
	}

	static void resetCronQueue(Cron... arr) {
		Cron cron;
		int i, j;
		int len = arr.length;
		synchronized (_lock) {
			for (i = 0; i < arr.length; i++) {
				if (!arr[i].calcu(System.currentTimeMillis())) {
					arr[i] = null;
					len--;
				}
			}
			if (len != arr.length) {
				final Cron a[] = new Cron[len];
				j = 0;
				for (i = 0; i < arr.length; i++) {
					if (arr[i] != null)
						a[j++] = arr[i];
				}
				arr = a;
			}
			for (i = arr.length - 1; i > 0; --i) {
				for (j = 0; j < i; ++j) {
					if (arr[j + 1]._tRun < arr[j]._tRun) {
						cron = arr[j];
						arr[j] = arr[j + 1];
						arr[j + 1] = cron;
					}
				}
			}
			for (i = arr.length - 1; i > 0; --i) {
				arr[i - 1]._next = arr[i];
			}
			_this._head = arr[0];
			_lock.notifyAll();
		}
	}

	private static final Object _lock = new Object();
	private static final CronMgr _this = new CronMgr();
	private Cron _head; //队头

	public void run() {
		Cron cron;
		long now;
		synchronized (_lock) {
			for (;;) { //将for与lock换了个位置，意思是：让它一股脑跑，跑完最后会wait；这时，其它线程就可以取锁了，取了锁，就可以加入cron
				if ((cron = _head) == null) {
					try {
						_lock.wait(); //如果队列为空，就等待，直到被唤醒
					} catch (InterruptedException e) {
					}
					continue;
				}
				now = System.currentTimeMillis();
				if (cron._tRun > now) {
					try {
						_lock.wait(cron._tRun - now); //如果还没有到处理的时间，消息轮循就应该等待一定时间
					} catch (InterruptedException e) {
					}
					continue;
				}
				_head = cron._next;
				cron._next = null;
				cron.dispatch(now);
				if (cron.calcu(now))
					add2CronQueue(cron);
			}
		}
	}

	private void add2CronQueue(final Cron o) {
		Cron o11 = _head;
		if (o11 == null || o._tRun < o11._tRun) {
			o._next = o11;
			_head = o;
			return;
		}

		// 在消息队列不为空的情况下，要按照时间顺序加入队列中
		// 这有点麻烦
		Cron o33 = o11._next;
		for (;;) {
			if (o33 == null) {
				o11._next = o;
				return;
			}
			if (o._tRun < o33._tRun) {
				o11._next = o;
				o._next = o33;
				return;
			}
			o11 = o33;
			o33 = o33._next;
		}
	}

	/**
	 * 定时任务的封装类，仅是封装基础数据
	 */
	static abstract class Cron implements Runnable {
		protected static final String TAG = "cron";
		/** 某些字段的初始值 */
		protected static final byte V_Init = -11;
		/** 停止定时任务的值 */
		protected static final byte V_StopCron = -88;
		/** 单向链表 */
		private Cron _next;
		/** 标识id */
		protected final int _id;
		/** 执行类，或者说执行的代码块 */
		protected final Object _runner;
		/** 记录最近的执行时间点 */
		protected long _tLastRun;
		/** 下一次执行的时间点 */
		protected long _tRun;
		/** 下一次是否要执行，与下一次执行的时间点tRun对应 */
		protected boolean _bRun;
		/** 已经执行次数 */
		protected int _nRun;

		protected Cron(int id, Object runner) {
			this._next = null;
			this._id = id;
			this._runner = runner;
			this._tLastRun = V_Init;
//		this._tRun = V_StopCron;
			this._bRun = false;
			this._nRun = 0;
		}

		private final void dispatch(long now) {
			if (!_bRun)
				return;
			_nRun++;
			System.out.println(Test.SDF.format(now) + "\t\t" + _runner + "\t\t" + Test.SDF.format(_tRun));
//			if (mIsRunAtTime && mExector.can0(true)) {
//				// mExector.preExecute0();
//				mExecTimes++;
//				// CoreUtils.TASK_THREAD_POOL.execute(this);
//				mLastRunTime = System.currentTimeMillis();
//			}
		}

		/**
		 * 计算下一个执行的时间点，_tRun和_bRun都将被更新。
		 *
		 * @return 返回false，表示任务结束了。
		 */
		protected abstract boolean calcu(long now);
	}
}
